import {
  computed, defineComponent, onMounted, reactive, ref, set, toRefs, watch,
} from '@vue/composition-api';
import {
  Cascader, DatePicker, FormModel, Input, Select,
} from 'ant-design-vue';
import KtButton from '../KtButton/index.vue';
import { SEARCH_PARAM_TYPE } from '@/common';
import './index.scss';

const componentMap = new Map();
componentMap
  .set(SEARCH_PARAM_TYPE.INPUT, Input)
  .set(SEARCH_PARAM_TYPE.SELECT, Select)
  .set(SEARCH_PARAM_TYPE.DATE, DatePicker)
  .set(SEARCH_PARAM_TYPE.DATE_RANGE, DatePicker.RangePicker)
  .set(SEARCH_PARAM_TYPE.Cascader, Cascader);

const KtSearch = defineComponent({
  name: 'KtSearch',
  inheritAttrs: false,
  props: {
    form: {
      type: Object,
      required: true,
    },
    searchParams: {
      type: Array,
      required: true,
    },
    searchActions: {
      type: Array,
      default: () => [],
    },
    layout: {
      type: String,
      default: () => 'inline',
    },
    isHasExport: {
      type: Boolean,
      default: () => true,
    },
  },
  emits: ['initRef', 'search', 'reset'],
  setup(props, { emit, refs }) {

    onMounted(() => {
      /**
       * SetupContext.refs 并非 Vue 3.0 的一部分, @vue/composition-api 将其暴露在 SetupContext 中只是临时提供一种变通方案。
       * 如果你依然选择在 setup() 中写 render 函数，那么你可以使用 SetupContext.refs 来访问模板引用，它等价于 Vue 2.x 中的 this.$refs
       */
      emit('initRef', refs.formRef);
    });

    const formModel = reactive({});
    props.searchParams.forEach((item) => {
      /**
       * 警告: set 和 del 并非 Vue 3 的一部分。
       * 由于 Vue 2.x 响应式系统的限制，我们在插件中提供该 API 作为添加响应式属性的一个变通方案。
       * 在 Vue 3 中，你只需要直接为属性赋值即可。
       */
      set(formModel, item.field, props.form[item.field]);
    });

    const params = ref([]);

    watch(() => props.searchParams, (value) => {
      if (value) {
        params.value = value;
      }
    }, { immediate: true });

    const defaultActions = [
      {
        label: '查询',
        type: 'primary',
        func: () => {
          emit('search');
        },
      },
    ];

    props.isHasExport && defaultActions.push({
      label: '导出',
      func: () => {
        emit('export');
      },
    });

    const actions = computed(() => [...defaultActions, ...props.searchActions]);

    const renderButton = (action) => {
      const { type, label, func } = action;
      return (
          <KtButton type={type} class='mr-6' onClick={() => func()}>
            { label }
          </KtButton>
      );
    };

    const getPlaceHolder = (param) => {
      switch (param.type) {
        case SEARCH_PARAM_TYPE.INPUT: {
          return '请输入';
        }
        case SEARCH_PARAM_TYPE.SELECT:
        case SEARCH_PARAM_TYPE.DATE:
        case SEARCH_PARAM_TYPE.Cascader: {
          return '请选择';
        }
        case SEARCH_PARAM_TYPE.DATE_RANGE: {
          return ['开始日期', '结束日期'];
        }
        default: break;
      }
    };

    watch(() => params, () => {
      // 获取异步选项的值
      params.value.forEach(async (param) => {
        if (param.asyncOptions) {
          param.options = await param.asyncOptions();
        }
      });
    }, { immediate: true });

    const getComponent = (param) => {
      // 默认change事件
      const on = (e) => {
        // 自定义了change事件 返回false不赋值
        if (param.componentProps && param.componentProps.change && !param.componentProps.change(e)) {
          return;
        }
        // 组件输入的值
        // eslint-disable-next-line vue/no-mutating-props
        props.form[param.field] = (e && e.target) ? e.target.value : e;
      };

      // props定义的custom事件
      const customEvents = {};
      Object.keys(param.componentProps || {}).forEach((key) => {
        if (param.componentProps[key] instanceof Function) {
          customEvents[key] = param.componentProps[key];
        }
      });

      /**
       * 设置默认的replaceFields
       * 以dicList的type和code作为key
       */
      watch(() => param.options, (value) => {
        if (value?.length && !param.replaceFields) {
          param.replaceFields = {
            label: 'type',
            value: 'code',
          };
          // 默认添加全部选项
          if (!param.options?.find((item) => item.type === '全部')) {
            param.options?.unshift({
              type: '全部',
              code: '',
            });
          }
        }
      }, { immediate: true });

      /**
       * 获取select组件的选项
       */
      const options = computed(() => param.options?.map((item) => ({
        label: item[param.replaceFields.label],
        value: item[param.replaceFields.value],
      })));

      // 渲染具体的输入组件
      const Component = componentMap.get(param.type);
      return (
          <Component
              placeholder={param.placeholder || getPlaceHolder(param)}
              value={props.form[param.field]}
              options={param.type === SEARCH_PARAM_TYPE.SELECT ? options.value : param.options}
              valueFormat={param.valueFormat}
              allowClear={false}
              vOn:change={on}
              props={{ ...param.componentProps }}
              attrs={{ ...param.componentProps }}
              { ...{ on: { ...customEvents } } }
          />
      );
    };

    // 渲染FormItem
    const renderItem = (param) => {
      const { field, label } = param;
      return (
          <FormModel.Item prop={field} label={label}>
            {
              getComponent(param)
            }
          </FormModel.Item>
      );
    };

    return () => {
      const { searchParams, layout } = toRefs(props);

      return (
       <div>
         <FormModel ref='formRef' layout={layout.value} props={{ model: props.form }}>
           {
             searchParams.value.map((param) => renderItem(param))
           }
         </FormModel>
         <div class='mt-4'>
           {
             actions.value.map((action) => renderButton(action))
           }
         </div>
       </div>
      );
    };
  },
});

export default KtSearch;
